﻿Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Imaging

Public Class OutlineTextControl
    Inherits FrameworkElement

    Private _textGeometry As Geometry
    Private _imageSource As ImageSource

#Region "DependencyProperties"

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly FontProperty As DependencyProperty = DependencyProperty.Register( _
        "Font", _
        GetType(FontFamily), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            New FontFamily("Meiryo"), _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Font() As FontFamily
        Get
            Return DirectCast(GetValue(FontProperty), FontFamily)
        End Get
        Set(ByVal value As FontFamily)
            SetValue(FontProperty, value)
        End Set
    End Property


    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly FontSizeProperty As DependencyProperty = DependencyProperty.Register( _
        "FontSize", _
        GetType(Double), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            48.0, _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property FontSize() As Double
        Get
            Return DirectCast(GetValue(FontSizeProperty), Double)
        End Get
        Set(ByVal value As Double)
            SetValue(FontSizeProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly FillProperty As DependencyProperty = DependencyProperty.Register( _
        "Fill", _
        GetType(Brush), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            New SolidColorBrush(Colors.White), _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Fill() As Brush
        Get
            Return DirectCast(GetValue(FillProperty), Brush)
        End Get
        Set(ByVal value As Brush)
            SetValue(FillProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly StrokeProperty As DependencyProperty = DependencyProperty.Register( _
        "Stroke", _
        GetType(Brush), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            New SolidColorBrush(Colors.Black), _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Stroke() As Brush
        Get
            Return DirectCast(GetValue(StrokeProperty), Brush)
        End Get
        Set(ByVal value As Brush)
            SetValue(StrokeProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly StrokeThicknessProperty As DependencyProperty = DependencyProperty.Register( _
        "StrokeThickness", _
        GetType(UShort), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            1US, _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property StrokeThickness() As UShort
        Get
            Return DirectCast(GetValue(StrokeThicknessProperty), UShort)
        End Get
        Set(ByVal value As UShort)
            SetValue(StrokeThicknessProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register( _
        "Text", _
        GetType(String), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            "", _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Text() As String
        Get
            Return DirectCast(GetValue(TextProperty), String)
        End Get
        Set(ByVal value As String)
            SetValue(TextProperty, value)
        End Set
    End Property


    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly BoldProperty As DependencyProperty = DependencyProperty.Register( _
        "Bold", _
        GetType(Boolean), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            False, _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Bold() As Boolean
        Get
            Return DirectCast(GetValue(BoldProperty), Boolean)
        End Get
        Set(ByVal value As Boolean)
            SetValue(BoldProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly ImageUriProperty As DependencyProperty = DependencyProperty.Register( _
        "ImageUri", _
        GetType(String), _
        GetType(OutlineTextControl), _
        New FrameworkPropertyMetadata( _
            "", _
            FrameworkPropertyMetadataOptions.AffectsRender, _
            New PropertyChangedCallback(AddressOf OnInvalidated), _
            Nothing))

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property ImageUri() As String
        Get
            Return DirectCast(GetValue(ImageUriProperty), String)
        End Get
        Set(ByVal value As String)
            SetValue(ImageUriProperty, value)
        End Set
    End Property

#End Region

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="d"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Shared Sub OnInvalidated(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        DirectCast(d, OutlineTextControl).CreateText()
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub CreateText()
        Dim fontStyle = FontStyles.Normal
        Dim fontWeight = If(Me.Bold, FontWeights.Bold, FontWeights.Medium)

        Dim formattedText = New FormattedText( _
            Me.Text, _
            System.Globalization.CultureInfo.CurrentUICulture, _
            Windows.FlowDirection.LeftToRight, _
            New Typeface(Me.Font, _
                         fontStyle, _
                         fontWeight, _
                         FontStretches.Normal), _
            Me.FontSize, _
            Brushes.Black)

        _textGeometry = formattedText.BuildGeometry(New Point(0, 0))

        Me.Width = _textGeometry.Bounds.Left + _textGeometry.Bounds.Width + Me.StrokeThickness
        Me.Height = _textGeometry.Bounds.Top + _textGeometry.Bounds.Height + Me.StrokeThickness
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="drawingContext"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnRender(ByVal drawingContext As DrawingContext)

        Const ICON_SIZE As Integer = 52
        Const ICON_MARGIN As Integer = 2

        If Not String.IsNullOrEmpty(Me.ImageUri) Then
            If _imageSource Is Nothing Then
                Dim source = New BitmapImage()
                source.BeginInit()
                source.CreateOptions = BitmapCreateOptions.IgnoreColorProfile
                source.UriSource = New Uri(Me.ImageUri)
                source.EndInit()

                _imageSource = source
            End If
            Dim top As Integer = CInt((Me.ActualHeight - ICON_SIZE) / 2) + ICON_MARGIN
            drawingContext.DrawImage(_imageSource, New Rect(-(ICON_SIZE + ICON_MARGIN), top, ICON_SIZE, ICON_SIZE))
        End If

        drawingContext.DrawGeometry(Me.Fill, New Pen(Me.Stroke, Me.StrokeThickness), _textGeometry)
    End Sub
End Class
